////////////////////////////////////////////////////////////////////////////////
// uftpd is a userspace ftp daemon using qt for network gui and file io.
// Copyright (C) 2008 Tobias Wich
// 
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
////////////////////////////////////////////////////////////////////////////////

#include <iostream>

#include "session.H"

using namespace std;
using namespace uftpd;

//==============================================================================
// class AbstractState
//==============================================================================

void AbstractState::tokenizeCmd(vector<string> & cmdList, string cmd) {
  size_t cmdSize= cmd.size();
  if ((cmdSize <= 2 ) || 
      ((cmd.at(cmdSize - 1) != '\n') && (cmd.at(cmdSize - 2) != 'r'))) {
    return 0;
  }
  //remove last 2 chars
  cmd = cmd.substr(0, cmdSize -= 2);

  stringstream ss;
  ss << cmd;

  //extract all tokens
  while(! ss.eof()) {
    string tmp;
    ss >> tmp;
    if (! tmp.empty()) {
      cmdList.push_back(tmp);
    }
  }
}

StatesE AbstractState::process(string cmd) {
  vector<string> cmdList;
  AbstractState::tokenizeCmd(cmdList, cmd);

  return processCmd(cmdList);
}

//==============================================================================
// class LoginState
//==============================================================================

bool LoginState::setUser(string userName) {
  mUser.clear();
  
  mUser = userName;
  //TODO: verify user
  
  return true;
}

bool LoginState::setPass(string password) {
  //TODO: verify password
  return true;
}

StatesE LoginState::processCmd(vector<string> & v) {
  //empty instuction
  if (v.empty()) {
    setReplyCode(ReplyCodeT(FTP_CMD_OK, string("")));
    return returnSelf();
  }

  // USER cmd sent
  if (v[0] == "USER" ) {
    if (v.size() == 2) {
      if (setUser(v[1])) {
	//username accepted
	setReplyCode(ReplyCodeT(FTP_USER_OK));
      } else {
	//username invalid
	setReplyCode(ReplyCodeT(FTP_NEED_ACCOUNT_FOR_LOGIN));
      }
    } else {
      //syntax error
    }
    return returnSelf();
  }

  // PASS cmd sent
  if (v[0] == "PASS") {
    if (v.size() == 2) {
      if (setPass(v[1])) {
	//password accepted
	setReplyCode(ReplyCodeT(FTP_LOGGED_IN));
	return CMD;
      } else {
	//password invalid -- behaviour of proftpd
	setReplyCode(ReplyCodeT(FTP_SERVICE_NA, "Wrong password, closing connection."));
      }
    } else {
      //syntax error
    }
  }

  cout << "tok#" << v.size() << " " << v[0] << endl;

  setReplyCode(ReplyCodeT(FTP_CMD_OK, string("")));
  return CMD;
}

//==============================================================================
// class CmdState
//==============================================================================

StatesE CmdState::processCmd(vector<string> & v) {
  //empty instuction
  if (v.empty()) {
    setReplyCode(ReplyCodeT(FTP_CMD_OK, string("")));
    return returnSelf();
  }

  cout << "tok#" << v.size() << " " << v[0] << endl;

  setReplyCode(ReplyCodeT(FTP_CMD_OK, string("")));
  return CMD;
}

//==============================================================================
// class SessionMachine
//==============================================================================

ReplyCodeT SessionMachine::processCmd(string cmd) {
  StatesE nextState = mCurState->process(cmd);
  ReplyCodeT & replyCode = mCurState->replyCode();

  // idicates a connection quit -- don't send anything
  if(replyCode.code() == FTP_SERVICE_NA) {
    //TODO: terminate thread and cleanup
  } else {
    setState(nextState);
  }

  return replyCode;
}
